<?php

namespace pmvc\tx;

use pmvc\log\Log;

/**
 * Utilities for transaction related things.
 *
 */
class TransactionUtil {

	private static $TRANSACTIONS = Array();

	/**
	 * Returns the current thread id.
	 */
	private static function getThreadId() {
		return function_exists("zend_thread_id")
			? zend_thread_id()
			: "thread-1";
	}

	/**
	 * Returns the transaction bound to the current
	 * thread or null if non existant.
	 * @return Transaction
	 */
	public static function getTransaction() {
		$threadId = self::getThreadId();
		return (array_key_exists($threadId, self::$TRANSACTIONS))
			? self::$TRANSACTIONS[$threadId] : null;
	}

	/**
	 * Returns an existing transaction or creates a new one if needed.
	 * @param TransactionProvider $provider
	 * @param bool $autoCommit
	 */
	public static function getOrCreateTransaction(TransactionProvider $provider, $autoCommit=false) {
		$threadId = self::getThreadId();
		if (!array_key_exists($threadId, self::$TRANSACTIONS)) {
			Log::trace(__CLASS__, "Creating new JoinedTransaction");
			self::$TRANSACTIONS[$threadId] = new JoinedTransaction($provider->createTransaction());
			self::$TRANSACTIONS[$threadId]->setAutoCommit($autoCommit);
		} else {
			Log::trace(__CLASS__, "Returning existing JoinedTransaction");
		}
		return self::$TRANSACTIONS[$threadId];
	}

	/**
	 * Starts a transaction bound to the current thread.
	 * A transaction is created if none exists.
	 * @param TransactionProvider $provider
	 * @param bool $autoCommit
	 */
	public static function startTransaction(TransactionProvider $provider, $autoCommit=false) {
		$tx = self::getOrCreateTransaction($provider, $autoCommit);
		$tx->start();
		return $tx;
	}

	/**
	 * Commits the transaction bound to the current thread.
	 * @param bool $force
	 */
	public static function commitTransaction($force=false) {
		$tx = self::getTransaction();
		if (isset($tx) && $tx!=null) {
			if ($force) {
				$tx->forceCommit();
			} else {
				$tx->commit();
			}
			if ($tx->isCommited()) {
				Log::trace(__CLASS__, "Clearing commited Transaction");
				$threadId = self::getThreadId();
				unset(self::$TRANSACTIONS[$threadId]);
			}
		}
	}

	/**
	 * Rolls back the transaction bound to the current thread.
	 */
	public static function rollbackTransaction() {
		$tx = self::getTransaction();
		if (isset($tx) && $tx!=null) {
			$tx->rollback();
			if ($tx->isRolledBack()) {
				Log::trace(__CLASS__, "Clearing rolled back Transaction");
				$threadId = self::getThreadId();
				unset(self::$TRANSACTIONS[$threadId]);
			}
		}
	}

}
?>